home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume9 / elm2 / patch02 < prev    next >
Encoding:
Internet Message Format  |  1987-04-30  |  15.1 KB

  1. Subject:  v09i064:  Fixed reply.c for ELM, Patch2
  2. Newsgroups: mod.sources, comp.sources.unix
  3. Approved: rs@mirror.TMC.COM
  4.  
  5. Submitted by: rs (Rich Salz)
  6. Mod.sources: Volume 9, Issue 64
  7. Archive-name: elm2/Patch2
  8.  
  9. [  Sorry about the delay on this one -- I had to dig it out of a
  10.    tape library...  --r$  ]
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line,
  14. # then unpack it by saving it in a file and typing "sh file".
  15. # If this archive is complete, you will see the message:
  16. #        "End of shell archive."
  17. # Contents:  reply.c
  18. # Wrapped by rs@mirror on Thu Apr 30 16:55:12 1987
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. echo shar: Extracting \"reply.c\" \(13964 characters\)
  21. if test -f reply.c ; then 
  22.   echo shar: Will not over-write existing file \"reply.c\"
  23. else
  24. sed "s/^X//" >reply.c <<'END_OF_reply.c'
  25. X/**        reply.c        **/
  26. X
  27. X/*** routine allows replying to the sender of the current message 
  28. X
  29. X     (C) Copyright 1985, Dave Taylor
  30. X***/
  31. X
  32. X#include "headers.h"
  33. X#include <errno.h>
  34. X
  35. X#ifndef BSD
  36. X#  include <sys/types.h>
  37. X#  include <sys/utsname.h>
  38. X#endif
  39. X
  40. X/** Note that this routine generates automatic header information
  41. X    for the subject and (obviously) to lines, but that these can
  42. X    be altered while in the editor composing the reply message! 
  43. X**/
  44. X
  45. Xchar *strip_parens(), *get_token();
  46. X
  47. Xextern int errno;
  48. X
  49. Xchar *error_name(), *strcat(), *strcpy();
  50. X
  51. Xint
  52. Xreply()
  53. X{
  54. X    /** Reply to the current message.  Returns non-zero iff
  55. X        the screen has to be rewritten. **/
  56. X
  57. X    char return_address[LONG_SLEN], subject[SLEN];
  58. X    int  return_value, form_letter;
  59. X
  60. X    form_letter = (header_table[current-1].status & FORM_LETTER);
  61. X
  62. X    get_return(return_address);
  63. X
  64. X    if (first_word(header_table[current-1].from, "To:")) {
  65. X      strcpy(subject, header_table[current-1].subject);
  66. X      if (form_letter)
  67. X        return_value = mail_filled_in_form(return_address, subject);
  68. X      else
  69. X        return_value = send(return_address, subject, TRUE, NO);
  70. X    }
  71. X    else if (header_table[current-1].subject[0] != '\0') {
  72. X      if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) ||
  73. X          (strncmp("RE:", header_table[current-1].subject, 3) == 0) ||
  74. X          (strncmp("re:", header_table[current-1].subject, 3) == 0)) 
  75. X        strcpy(subject, header_table[current-1].subject);
  76. X      else {
  77. X        strcpy(subject,"Re: ");
  78. X        strcat(subject,header_table[current-1].subject); 
  79. X      }
  80. X      if (form_letter)
  81. X        return_value = mail_filled_in_form(return_address, subject);
  82. X      else
  83. X        return_value = send(return_address, subject, TRUE, NO);
  84. X    }
  85. X    else
  86. X      if (form_letter)
  87. X        return_value = mail_filled_in_form(return_address, 
  88. X                        "Filled in Form");
  89. X      else
  90. X        return_value = send(return_address, "Re: your mail", TRUE, NO);
  91. X
  92. X    return(return_value);
  93. X}
  94. X
  95. Xint
  96. Xreply_to_everyone()
  97. X{
  98. X    /** Reply to everyone who received the current message.  
  99. X        This includes other people in the 'To:' line and people
  100. X        in the 'Cc:' line too.  Returns non-zero iff the screen 
  101. X            has to be rewritten. **/
  102. X
  103. X    char return_address[LONG_SLEN], subject[SLEN];
  104. X    char full_address[VERY_LONG_STRING];
  105. X    int  return_value;
  106. X
  107. X    get_return(return_address);
  108. X
  109. X    strcpy(full_address, return_address);    /* sender gets copy */
  110. X    
  111. X    get_and_expand_everyone(return_address, full_address);
  112. X
  113. X    if (header_table[current-1].subject[0] != '\0') {
  114. X      if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) ||
  115. X          (strncmp("RE:", header_table[current-1].subject, 3) == 0) ||
  116. X          (strncmp("re:", header_table[current-1].subject, 3) == 0)) 
  117. X        strcpy(subject, header_table[current-1].subject);
  118. X      else {
  119. X        strcpy(subject,"Re: ");
  120. X        strcat(subject,header_table[current-1].subject); 
  121. X      }
  122. X      return_value = send(full_address, subject, TRUE, NO);
  123. X    }
  124. X    else
  125. X      return_value = send(full_address, "Re: your mail", TRUE, NO);
  126. X
  127. X    return(return_value);
  128. X
  129. X}
  130. X
  131. Xint
  132. Xforward()
  133. X{
  134. X    /** Forward the current message.  What this actually does is
  135. X        to set auto_copy to true, then call 'send' to get the 
  136. X        address and route the mail. 
  137. X    **/
  138. X
  139. X    char subject[SLEN], address[VERY_LONG_STRING];
  140. X    int  original_cc, results, edit_msg = FALSE;
  141. X
  142. X    original_cc = auto_copy;
  143. X    address[0] = '\0';
  144. X
  145. X    if (header_table[current-1].status & FORM_LETTER)
  146. X      PutLine0(LINES-3,COLUMNS-40,"<no editing allowed>");
  147. X    else {
  148. X      edit_msg = (want_to("Edit outgoing message (y/n) ? ",'y',FALSE)!='n');
  149. X      Write_to_screen("%s", 1, edit_msg? "Yes" : "No");
  150. X    }
  151. X
  152. X    auto_cc = TRUE;            /* we want a copy */
  153. X
  154. X    if (strlen(header_table[current-1].subject) > 0) {
  155. X      strcpy(subject,header_table[current-1].subject); 
  156. X      results = send(address, subject, edit_msg,
  157. X        header_table[current-1].status & FORM_LETTER? 
  158. X        PREFORMATTED : allow_forms);
  159. X    }
  160. X    else
  161. X      results = send(address, "Forwarded Mail...", edit_msg, 
  162. X        header_table[current-1].status & FORM_LETTER? 
  163. X        PREFORMATTED : allow_forms);
  164. X    
  165. X    auto_copy = original_cc;
  166. X
  167. X    return(results);
  168. X}
  169. X
  170. Xget_and_expand_everyone(return_address, full_address)
  171. Xchar *return_address, *full_address;
  172. X{
  173. X    /** Read the current message, extracting addresses from the 'To:'
  174. X        and 'Cc:' lines.   As each address is taken, ensure that it
  175. X        isn't to the author of the message NOR to us.  If neither,
  176. X        prepend with current return address and append to the 
  177. X        'full_address' string.
  178. X    **/
  179. X
  180. X    char ret_address[LONG_SLEN], buf[LONG_SLEN], new_address[LONG_SLEN],
  181. X     address[LONG_SLEN], comment[LONG_SLEN];
  182. X    int  in_message = 1, first_pass = 0, index;
  183. X
  184. X    /** First off, get to the first line of the message desired **/
  185. X
  186. X    if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
  187. X    dprint3(1,"Error: seek %ld resulted in errno %s (%s)\n", 
  188. X         header_table[current-1].offset, error_name(errno), 
  189. X         "get_and_expand_everyone");
  190. X    error2("ELM [seek] couldn't read %d bytes into file (%s)",
  191. X           header_table[current-1].offset, error_name(errno));
  192. X    return;
  193. X    }
  194. X    /** okay!  Now we're there!  **/
  195. X
  196. X    /** let's fix the ret_address to reflect the return address of this
  197. X    message with '%s' instead of the persons login name... **/
  198. X
  199. X    translate_return(return_address, ret_address);
  200. X
  201. X    /** now let's parse the actual message! **/
  202. X
  203. X    while (in_message) {
  204. X      in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
  205. X      if (first_word(buf, "From ") && first_pass++ != 0) 
  206. X    in_message = FALSE;
  207. X      else if (first_word(buf, "To:") || first_word(buf, "Cc:") ||
  208. X           first_word(buf, "CC:") || first_word(buf, "cc:")) {
  209. X    do {
  210. X      no_ret(buf);
  211. X
  212. X      /** we have a buffer with a list of addresses, each of either the
  213. X          form "address (name)" or "name <address>".  Our mission, should
  214. X          we decide not to be too lazy, is to break it into the two parts.
  215. X      **/
  216. X          
  217. X      if (!whitespace(buf[0]))
  218. X        index = chloc(buf, ':')+1;        /* skip header field */
  219. X      else
  220. X        index = 0;                /* skip whitespace   */
  221. X
  222. X      while (break_down_tolist(buf, &index, address, comment)) {
  223. X
  224. X        if (okay_address(address, return_address)) {
  225. X          sprintf(new_address, ret_address, address);
  226. X          optimize_and_add(new_address, full_address);
  227. X        }
  228. X      }
  229. X
  230. X          in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
  231. X
  232. X      if (in_message) dprint1(1,"> %s", buf);
  233. X    
  234. X    } while (in_message && whitespace(buf[0]));
  235. X
  236. X      }
  237. X      else if (strlen(buf) < 2)    /* done with header */
  238. X     in_message = FALSE;
  239. X    }
  240. X}
  241. X
  242. Xint
  243. Xokay_address(address, return_address)
  244. Xchar *address, *return_address;
  245. X{
  246. X    /** This routine checks to ensure that the address we just got
  247. X        from the "To:" or "Cc:" line isn't us AND isn't the person    
  248. X        who sent the message.  Returns true iff neither is the case **/
  249. X
  250. X    char our_address[SLEN];
  251. X    struct addr_rec  *alternatives;
  252. X
  253. X    if (in_string(address, return_address))
  254. X      return(FALSE);
  255. X
  256. X    sprintf(our_address, "%s!%s", hostname, username);
  257. X
  258. X    if (in_string(address, our_address))
  259. X      return(FALSE);
  260. X
  261. X    sprintf(our_address, "%s@%s", username, hostname);
  262. X      
  263. X    if (in_string(address, our_address))
  264. X      return(FALSE);
  265. X
  266. X    alternatives = alternative_addresses;
  267. X
  268. X    while (alternatives != NULL) {
  269. X      if (in_string(address, alternatives->address))
  270. X        return(FALSE);
  271. X      alternatives = alternatives->next;
  272. X    }
  273. X
  274. X    return(TRUE);
  275. X}
  276. X        
  277. Xoptimize_and_add(new_address, full_address)
  278. Xchar *new_address, *full_address;
  279. X{
  280. X    /** This routine will add the new address to the list of addresses
  281. X        in the full address buffer IFF it doesn't already occur.  It
  282. X        will also try to fix dumb hops if possible, specifically hops
  283. X        of the form ...a!b...!a... and hops of the form a@b@b etc 
  284. X    **/
  285. X
  286. X    register int len, host_count = 0, i;
  287. X    char     hosts[MAX_HOPS][SLEN];    /* array of machine names */
  288. X    char     *host, *addrptr;
  289. X
  290. X    if (in_string(full_address, new_address))
  291. X      return(1);    /* duplicate address */
  292. X
  293. X    /** optimize **/
  294. X    /*  break down into a list of machine names, checking as we go along */
  295. X    
  296. X    addrptr = (char *) new_address;
  297. X
  298. X    while ((host = get_token(addrptr, "!", 1)) != NULL) {
  299. X      for (i = 0; i < host_count && ! equal(hosts[i], host); i++)
  300. X          ;
  301. X
  302. X      if (i == host_count) {
  303. X        strcpy(hosts[host_count++], host);
  304. X        if (host_count == MAX_HOPS) {
  305. X           dprint1(2,
  306. X              "Error: hit max_hops limit trying to build return address (%s)\n",
  307. X              "optimize_and_add");
  308. X           error("Can't build return address - hit MAX_HOPS limit!");
  309. X           return(1);
  310. X        }
  311. X      }
  312. X      else 
  313. X        host_count = i + 1;
  314. X      addrptr = NULL;
  315. X    }
  316. X
  317. X    /** fix the ARPA addresses, if needed **/
  318. X    
  319. X    if (chloc(hosts[host_count-1], '@') > -1)
  320. X      fix_arpa_address(hosts[host_count-1]);
  321. X      
  322. X    /** rebuild the address.. **/
  323. X
  324. X    new_address[0] = '\0';
  325. X
  326. X    for (i = 0; i < host_count; i++)
  327. X      sprintf(new_address, "%s%s%s", new_address, 
  328. X              new_address[0] == '\0'? "" : "!",
  329. X              hosts[i]);
  330. X
  331. X    if (full_address[0] == '\0')
  332. X      strcpy(full_address, new_address);
  333. X    else {
  334. X      len = strlen(full_address);
  335. X      full_address[len  ] = ',';
  336. X      full_address[len+1] = ' ';
  337. X      full_address[len+2] = '\0';
  338. X      strcat(full_address, new_address);
  339. X    }
  340. X
  341. X    return(0);
  342. X}
  343. X
  344. Xget_return_name(address, name, shift_lower)
  345. Xchar *address, *name;
  346. Xint   shift_lower;
  347. X{
  348. X    /** Given the address (either a single address or a combined list 
  349. X        of addresses) extract the login name of the first person on
  350. X        the list and return it as 'name'.  Modified to stop at
  351. X        any non-alphanumeric character. **/
  352. X
  353. X    /** An important note to remember is that it isn't vital that this
  354. X        always returns just the login name, but rather that it always
  355. X        returns the SAME name.  If the persons' login happens to be,
  356. X        for example, joe.richards, then it's arguable if the name 
  357. X        should be joe, or the full login.  It's really immaterial, as
  358. X        indicated before, so long as we ALWAYS return the same name! **/
  359. X
  360. X    /** Another note: modified to return the argument as all lowercase
  361. X        always, unless shift_lower is FALSE... **/
  362. X
  363. X    char single_address[LONG_SLEN];
  364. X    register int i, loc, index = 0;
  365. X
  366. X    dprint2(6,"get_return_name called with (%s, <>, shift=%s)\n", 
  367. X           address, onoff(shift_lower));
  368. X
  369. X    /* First step - copy address up to a comma, space, or EOLN */
  370. X
  371. X    for (i=0; address[i] != ',' && ! whitespace(address[i]) && 
  372. X         address[i] != '\0'; i++)
  373. X      single_address[i] = address[i];
  374. X    single_address[i] = '\0';
  375. X
  376. X    /* Now is it an ARPA address?? */
  377. X
  378. X    if ((loc = chloc(single_address, '@')) != -1) {      /* Yes */
  379. X
  380. X      /* At this point the algorithm is to keep shifting our copy 
  381. X         window left until we hit a '!'.  The login name is then
  382. X             located between the '!' and the first metacharacter to 
  383. X         it's right (ie '%', ':' or '@'). */
  384. X
  385. X      for (i=loc; single_address[i] != '!' && i > -1; i--)
  386. X          if (single_address[i] == '%' || 
  387. X              single_address[i] == ':' ||
  388. X              single_address[i] == '.' ||    /* no domains */
  389. X          single_address[i] == '@') loc = i-1;
  390. X    
  391. X      if (i < 0 || single_address[i] == '!') i++;
  392. X
  393. X      for (index = 0; index < loc - i + 1; index++)
  394. X        if (shift_lower)
  395. X          name[index] = tolower(single_address[index+i]);
  396. X        else
  397. X          name[index] = single_address[index+i];
  398. X      name[index] = '\0';
  399. X    }
  400. X    else {    /* easier - standard USENET address */
  401. X
  402. X      /* This really is easier - we just cruise left from the end of
  403. X         the string until we hit either a '!' or the beginning of the
  404. X             line.  No sweat. */
  405. X
  406. X      loc = strlen(single_address)-1;     /* last char */
  407. X
  408. X      for (i = loc; single_address[i] != '!' && single_address[i] != '.' 
  409. X           && i > -1; i--)
  410. X         if (shift_lower)
  411. X           name[index++] = tolower(single_address[i]);
  412. X         else
  413. X           name[index++] = single_address[i];
  414. X      name[index] = '\0';
  415. X      reverse(name);
  416. X    }
  417. X}
  418. X
  419. Xint
  420. Xbreak_down_tolist(buf, index, address, comment)
  421. Xchar *buf, *address, *comment;
  422. Xint  *index;
  423. X{
  424. X    /** This routine steps through "buf" and extracts a single address
  425. X        entry.  This entry can be of any of the following forms;
  426. X
  427. X        address (name)
  428. X        name <address>
  429. X        address
  430. X    
  431. X        Once it's extracted a single entry, it will then return it as
  432. X        two tokens, with 'name' (e.g. comment) surrounded by parens.
  433. X        Returns ZERO if done with the string...
  434. X    **/
  435. X
  436. X    char buffer[LONG_STRING];
  437. X    register int i, loc = 0;
  438. X
  439. X    if (*index > strlen(buf)) return(FALSE);
  440. X
  441. X    while (whitespace(buf[*index])) (*index)++;
  442. X
  443. X    if (*index > strlen(buf)) return(FALSE);
  444. X
  445. X    /** Now we're pointing at the first character of the token! **/
  446. X
  447. X    while (buf[*index] != ',' && buf[*index] != '\0')
  448. X      buffer[loc++] = buf[(*index)++];
  449. X
  450. X    (*index)++;
  451. X
  452. X    while (whitespace(buffer[loc])) loc--;    /* remove trailing whitespace */
  453. X
  454. X    buffer[loc] = '\0';
  455. X
  456. X    if (strlen(buffer) == 0) return(FALSE);
  457. X
  458. X    dprint1(5, "\n* got \"%s\"\n", buffer);
  459. X
  460. X    if (buffer[loc-1] == ')') {    /*   address (name)  format */
  461. X      for (loc = 0;buffer[loc] != '(' && loc < strlen(buffer); loc++)
  462. X        /* get to the opening comment character... */ ;
  463. X
  464. X      loc--;    /* back up to just before the paren */
  465. X      while (whitespace(buffer[loc])) loc--;    /* back up */
  466. X
  467. X      /** get the address field... **/
  468. X
  469. X      for (i=0; i <= loc; i++)
  470. X        address[i] = buffer[i];
  471. X      address[i] = '\0';
  472. X
  473. X      /** now get the comment field, en toto! **/
  474. X
  475. X      loc = 0;
  476. X
  477. X      for (i = chloc(buffer, '('); i < strlen(buffer); i++)
  478. X        comment[loc++] = buffer[i];
  479. X      comment[loc] = '\0';
  480. X    }
  481. X    else if (buffer[loc-1] == '>') {    /*   name <address>  format */
  482. X      dprint0(7, "\tcomment <address>\n");
  483. X      for (loc = 0;buffer[loc] != '<' && loc < strlen(buffer); loc++)
  484. X        /* get to the opening comment character... */ ;
  485. X      while (whitespace(buffer[loc])) loc--;    /* back up */
  486. X
  487. X      /** get the comment field... **/
  488. X
  489. X      comment[0] = '(';
  490. X      for (i=1; i < loc; i++)
  491. X        comment[i] = buffer[i-1];
  492. X      comment[i++] = ')';
  493. X      comment[i] = '\0';
  494. X
  495. X      /** now get the address field, en toto! **/
  496. X
  497. X      loc = 0;
  498. X
  499. X      for (i = chloc(buffer,'<') + 1; i < strlen(buffer) - 1; i++)
  500. X        address[loc++] = buffer[i];
  501. X    
  502. X      address[loc] = '\0';
  503. X    }
  504. X    else {
  505. X      strcpy(address, buffer);
  506. X      comment[0] = '\0';
  507. X    }
  508. X
  509. X    dprint2(5,"-- returning '%s' '%s'\n", address, comment);
  510. X
  511. X    return(TRUE);
  512. X}
  513. END_OF_reply.c
  514. if test 13964 -ne `wc -c <reply.c`; then
  515.     echo shar: \"reply.c\" unpacked with wrong size!?
  516. fi
  517. # end of overwriting check
  518. fi
  519. echo shar: End of shell archive.
  520. exit 0
  521.  
  522.